﻿// JScript File
/// <reference path="_namespace.js" />
/// <reference path="Vector3.js" />
/// <reference path="../geometry/Math.js"/>

/*****************************************************************************
Ajax library class definition. Kevin Robinson 2006.
Class: ajax.math.Matrix
/*****************************************************************************/

ajax.lang.addNamespace("ajax.math");
ajax.lang.imports("ajax.geometry.Math");

//-----------------------------------------------------------------------------
ajax.math.Matrix = function()
{///<summary>Creates a 4X4 Matrix</summary>
    // Removed inheritance for speed
    //ajax.math.Matrix.superConstructor.call(this);
    
    // Store 4 X 4 matrix
	this.m = ajax.lang.multiDimensionalArray(4, 4);
	// Make Identity as default
	this.m[0][0] = 1;
	this.m[1][1] = 1;
	this.m[2][2] = 1;
	this.m[3][3] = 1;	
	
	// Hook up statics as instance methods also
	this.identity               = ajax.math.Matrix.identity; 
	this.scaling                = ajax.math.Matrix.scaling;
	this.translation            = ajax.math.Matrix.translation;
		
	this.rotateX                = ajax.math.Matrix.rotateX;
	this.rotateY                = ajax.math.Matrix.rotateY;
	this.rotateZ                = ajax.math.Matrix.rotateZ;
	
	this.rotateYawPitchRoll     = ajax.math.Matrix.rotateYawPitchRoll;
	this.transpose              = ajax.math.Matrix.transpose;	
	this.transposeAdjoint       = ajax.math.Matrix.transposeAdjoint;	
}

//-----------------------------------------------------------------------------
//ajax.lang.extend("ajax.math.Matrix", "ajax.BaseObject"); // Inherit
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Members, things you do to a Matrix
ajax.math.Matrix.invert = function(mat)
{///<returns type="ajax.math.Matrix">Returns the inverse of the passed matrix</returns>
    return mat.inverse();
}
ajax.math.Matrix.prototype.invert                    = function()
{///<summary>Inverts this matrix</summary>
	this.m = ajax.math.Matrix.inverse(this).m;
}

ajax.math.Matrix.prototype.scale                     = function(scale)
{///<summary>Scales this matrix</summary>
    ajax.math.Matrix.scale(this, scale);
}

ajax.math.Matrix.prototype.inverse                  = function()
{///<returns type="ajax.math.Matrix">Returns the inverse of this matrix</returns>
    return ajax.math.Matrix.inverse(this);
}


// These are *would be* operator overloads...and return a new object.
ajax.math.Matrix.prototype.multiply                  = function(b)
{///<summary>Multiplies this matrix by another one (b). Like (this)a * b, or world *= b.</summary>
    this.m = ajax.math.Matrix.multiply(this, b).m;
}

ajax.math.Matrix.prototype.multiplyReversed = function(a)
{///<summary>Multiplies this matrix by another one (b). Like b * (this)a, or world = b * world.</summary>
    this.m = ajax.math.Matrix.multiply(a, this).m;
}

ajax.math.Matrix.prototype.determinant               = function()
{///<returns type="number"/>
    return ajax.math.Matrix.determinant(this);
}

// Things you can do with a matrix instance
ajax.math.Matrix.prototype.transformVertices         = function(vb)
{///<returns type="Array" elementType="ajax.math.Vector3" >Transforms the vertex array passed</returns>
    return ajax.math.Matrix.transformVertices(this, vb);
}	

ajax.math.Matrix.prototype.transformVertex           = function(vertex)
{///<returns type="ajax.math.Vector3">Transforms a vertex by this matrix</returns>
    return ajax.math.Matrix.transformVertex(this, vertex);   
}

ajax.math.Matrix.prototype.transformFaceNormals      = function(faces)
{///<returns type="Array" elementType="ajax.math.Vector3"/>
    return ajax.math.Matrix.transformFaceNormals(this, faces);
}

ajax.math.Matrix.prototype.transformNormal           = function(normal)
{///<returns type="ajax.math.Vector3"/>
    return ajax.math.Matrix.transformNormal(this, normal);    
}

ajax.math.Matrix.prototype.toString                  = function()
{
    var ret = "";
    for (var i = 0; i < 4; i++)
        ret += this.m[i][0] + ", " + this.m[i][1] + ", " + this.m[i][2] + ", " + this.m[i][3] + "\n";
    return ret;    
}

//-----------------------------------------------------------------------------
ajax.math.Matrix.cast = function(obj)
{///<returns type="ajax.math.Matrix"/>
    return obj;
}

//-----------------------------------------------------------------------------
// Statics - Return different Types of Matrix
ajax.math.Matrix.identity                = function()
{///<returns type="ajax.math.Matrix"/>
	return new ajax.math.Matrix();
}

ajax.math.Matrix.scaling                 = function(Vector3scale)
{///<returns type="ajax.math.Matrix"/>
	var result = new ajax.math.Matrix();
	result.m[0][0] = Vector3scale.x;
	result.m[1][1] = Vector3scale.y;
	result.m[2][2] = Vector3scale.z;
	return result;
}

ajax.math.Matrix.translation             = function(Vector3translation)
{///<returns type="ajax.math.Matrix"/>
	var result = new ajax.math.Matrix();
	result.m[3][0] = Vector3translation.x;
	result.m[3][1] = Vector3translation.y;
	result.m[3][2] = Vector3translation.z;

	return result;
}



ajax.math.Matrix.rotateX                 = function(floatangle)
{///<returns type="ajax.math.Matrix"/>
	var cos = Math.cos(floatangle);
	var sin = Math.sin(floatangle);

	var result = new ajax.math.Matrix();
	result.m[1][1] = cos;
	result.m[1][2] = sin;
	result.m[2][1] = -sin;
	result.m[2][2] = cos;

	return result;
}

ajax.math.Matrix.rotateY                 = function(floatangle)
{///<returns type="ajax.math.Matrix"/>
	var cos = Math.cos(floatangle);
	var sin = Math.sin(floatangle);

	var result = new ajax.math.Matrix();
	result.m[0][0] = cos;
	result.m[0][2] = -sin;
	result.m[2][0] = sin;
	result.m[2][2] = cos;    
	return result;
}

ajax.math.Matrix.rotateZ                 = function(floatangle)
{///<returns type="ajax.math.Matrix"/>
	var cos = Math.cos(floatangle);
	var sin = Math.sin(floatangle);

	var result = new ajax.math.Matrix();
	result.m[0][0] = cos;
	result.m[0][1] = sin;
	result.m[1][0] = -sin;
	result.m[1][1] = cos;

	return result;
}




ajax.math.Matrix.rotateYawPitchRoll    = function(yaw, pitch, roll)
{///<returns type="ajax.math.Matrix"/>
	var result = ajax.math.Matrix.rotateY(yaw);
	result.multiplyReversed(ajax.math.Matrix.rotateX(pitch));
	result.multiplyReversed(ajax.math.Matrix.rotateZ(roll));

	return result;
}

ajax.math.Matrix.inverse                 = function(mat)
{///<returns type="number"/>
	var ret = new ajax.math.Matrix();
	var det = mat.determinant();
	var t00 = mat.m[1][2] * mat.m[2][3] * mat.m[3][1] - mat.m[1][3] * mat.m[2][2] * mat.m[3][1] + mat.m[1][3] * mat.m[2][1] * mat.m[3][2] - mat.m[1][1] * mat.m[2][3] * mat.m[3][2] - mat.m[1][2] * mat.m[2][1] * mat.m[3][3] + mat.m[1][1] * mat.m[2][2] * mat.m[3][3];
	var t01 = mat.m[0][3] * mat.m[2][2] * mat.m[3][1] - mat.m[0][2] * mat.m[2][3] * mat.m[3][1] - mat.m[0][3] * mat.m[2][1] * mat.m[3][2] + mat.m[0][1] * mat.m[2][3] * mat.m[3][2] + mat.m[0][2] * mat.m[2][1] * mat.m[3][3] - mat.m[0][1] * mat.m[2][2] * mat.m[3][3];
	var t02 = mat.m[0][2] * mat.m[1][3] * mat.m[3][1] - mat.m[0][3] * mat.m[1][2] * mat.m[3][1] + mat.m[0][3] * mat.m[1][1] * mat.m[3][2] - mat.m[0][1] * mat.m[1][3] * mat.m[3][2] - mat.m[0][2] * mat.m[1][1] * mat.m[3][3] + mat.m[0][1] * mat.m[1][2] * mat.m[3][3];
	var t03 = mat.m[0][3] * mat.m[1][2] * mat.m[2][1] - mat.m[0][2] * mat.m[1][3] * mat.m[2][1] - mat.m[0][3] * mat.m[1][1] * mat.m[2][2] + mat.m[0][1] * mat.m[1][3] * mat.m[2][2] + mat.m[0][2] * mat.m[1][1] * mat.m[2][3] - mat.m[0][1] * mat.m[1][2] * mat.m[2][3];
	var t10 = mat.m[1][3] * mat.m[2][2] * mat.m[3][0] - mat.m[1][2] * mat.m[2][3] * mat.m[3][0] - mat.m[1][3] * mat.m[2][0] * mat.m[3][2] + mat.m[1][0] * mat.m[2][3] * mat.m[3][2] + mat.m[1][2] * mat.m[2][0] * mat.m[3][3] - mat.m[1][0] * mat.m[2][2] * mat.m[3][3];
	var t11 = mat.m[0][2] * mat.m[2][3] * mat.m[3][0] - mat.m[0][3] * mat.m[2][2] * mat.m[3][0] + mat.m[0][3] * mat.m[2][0] * mat.m[3][2] - mat.m[0][0] * mat.m[2][3] * mat.m[3][2] - mat.m[0][2] * mat.m[2][0] * mat.m[3][3] + mat.m[0][0] * mat.m[2][2] * mat.m[3][3];
	var t12 = mat.m[0][3] * mat.m[1][2] * mat.m[3][0] - mat.m[0][2] * mat.m[1][3] * mat.m[3][0] - mat.m[0][3] * mat.m[1][0] * mat.m[3][2] + mat.m[0][0] * mat.m[1][3] * mat.m[3][2] + mat.m[0][2] * mat.m[1][0] * mat.m[3][3] - mat.m[0][0] * mat.m[1][2] * mat.m[3][3];
	var t13 = mat.m[0][2] * mat.m[1][3] * mat.m[2][0] - mat.m[0][3] * mat.m[1][2] * mat.m[2][0] + mat.m[0][3] * mat.m[1][0] * mat.m[2][2] - mat.m[0][0] * mat.m[1][3] * mat.m[2][2] - mat.m[0][2] * mat.m[1][0] * mat.m[2][3] + mat.m[0][0] * mat.m[1][2] * mat.m[2][3];
	var t20 = mat.m[1][1] * mat.m[2][3] * mat.m[3][0] - mat.m[1][3] * mat.m[2][1] * mat.m[3][0] + mat.m[1][3] * mat.m[2][0] * mat.m[3][1] - mat.m[1][0] * mat.m[2][3] * mat.m[3][1] - mat.m[1][1] * mat.m[2][0] * mat.m[3][3] + mat.m[1][0] * mat.m[2][1] * mat.m[3][3];
	var t21 = mat.m[0][3] * mat.m[2][1] * mat.m[3][0] - mat.m[0][1] * mat.m[2][3] * mat.m[3][0] - mat.m[0][3] * mat.m[2][0] * mat.m[3][1] + mat.m[0][0] * mat.m[2][3] * mat.m[3][1] + mat.m[0][1] * mat.m[2][0] * mat.m[3][3] - mat.m[0][0] * mat.m[2][1] * mat.m[3][3];
	var t22 = mat.m[0][1] * mat.m[1][3] * mat.m[3][0] - mat.m[0][3] * mat.m[1][1] * mat.m[3][0] + mat.m[0][3] * mat.m[1][0] * mat.m[3][1] - mat.m[0][0] * mat.m[1][3] * mat.m[3][1] - mat.m[0][1] * mat.m[1][0] * mat.m[3][3] + mat.m[0][0] * mat.m[1][1] * mat.m[3][3];
	var t23 = mat.m[0][3] * mat.m[1][1] * mat.m[2][0] - mat.m[0][1] * mat.m[1][3] * mat.m[2][0] - mat.m[0][3] * mat.m[1][0] * mat.m[2][1] + mat.m[0][0] * mat.m[1][3] * mat.m[2][1] + mat.m[0][1] * mat.m[1][0] * mat.m[2][3] - mat.m[0][0] * mat.m[1][1] * mat.m[2][3];
	var t30 = mat.m[1][2] * mat.m[2][1] * mat.m[3][0] - mat.m[1][1] * mat.m[2][2] * mat.m[3][0] - mat.m[1][2] * mat.m[2][0] * mat.m[3][1] + mat.m[1][0] * mat.m[2][2] * mat.m[3][1] + mat.m[1][1] * mat.m[2][0] * mat.m[3][2] - mat.m[1][0] * mat.m[2][1] * mat.m[3][2];
	var t31 = mat.m[0][1] * mat.m[2][2] * mat.m[3][0] - mat.m[0][2] * mat.m[2][1] * mat.m[3][0] + mat.m[0][2] * mat.m[2][0] * mat.m[3][1] - mat.m[0][0] * mat.m[2][2] * mat.m[3][1] - mat.m[0][1] * mat.m[2][0] * mat.m[3][2] + mat.m[0][0] * mat.m[2][1] * mat.m[3][2];
	var t32 = mat.m[0][2] * mat.m[1][1] * mat.m[3][0] - mat.m[0][1] * mat.m[1][2] * mat.m[3][0] - mat.m[0][2] * mat.m[1][0] * mat.m[3][1] + mat.m[0][0] * mat.m[1][2] * mat.m[3][1] + mat.m[0][1] * mat.m[1][0] * mat.m[3][2] - mat.m[0][0] * mat.m[1][1] * mat.m[3][2];
	var t33 = mat.m[0][1] * mat.m[1][2] * mat.m[2][0] - mat.m[0][2] * mat.m[1][1] * mat.m[2][0] + mat.m[0][2] * mat.m[1][0] * mat.m[2][1] - mat.m[0][0] * mat.m[1][2] * mat.m[2][1] - mat.m[0][1] * mat.m[1][0] * mat.m[2][2] + mat.m[0][0] * mat.m[1][1] * mat.m[2][2];
	ret.m[0][0] = t00;
	ret.m[0][1] = t01;
	ret.m[0][2] = t02;
	ret.m[0][3] = t03;
	ret.m[1][0] = t10;
	ret.m[1][1] = t11;
	ret.m[1][2] = t12;
	ret.m[1][3] = t13;
	ret.m[2][0] = t20;
	ret.m[2][1] = t21;
	ret.m[2][2] = t22;
	ret.m[2][3] = t23;
	ret.m[3][0] = t30;
	ret.m[3][1] = t31;
	ret.m[3][2] = t32;
	ret.m[3][3] = t33;
	ret.scale(1/det);

	return ret;
}


ajax.math.Matrix.determinant                 = function(mat)
{///<returns type="number"/>
	var det;
	det = 
		mat.m[0][3] * mat.m[1][2] * mat.m[2][1] * mat.m[3][0] - mat.m[0][2] * mat.m[1][3] * mat.m[2][1] * mat.m[3][0] - mat.m[0][3] * mat.m[1][1] * mat.m[2][2] * mat.m[3][0] + mat.m[0][1] * mat.m[1][3] * mat.m[2][2] * mat.m[3][0] +
		mat.m[0][2] * mat.m[1][1] * mat.m[2][3] * mat.m[3][0] - mat.m[0][1] * mat.m[1][2] * mat.m[2][3] * mat.m[3][0] - mat.m[0][3] * mat.m[1][2] * mat.m[2][0] * mat.m[3][1] + mat.m[0][2] * mat.m[1][3] * mat.m[2][0] * mat.m[3][1] +
		mat.m[0][3] * mat.m[1][0] * mat.m[2][2] * mat.m[3][1] - mat.m[0][0] * mat.m[1][3] * mat.m[2][2] * mat.m[3][1] - mat.m[0][2] * mat.m[1][0] * mat.m[2][3] * mat.m[3][1] + mat.m[0][0] * mat.m[1][2] * mat.m[2][3] * mat.m[3][1] +
		mat.m[0][3] * mat.m[1][1] * mat.m[2][0] * mat.m[3][2] - mat.m[0][1] * mat.m[1][3] * mat.m[2][0] * mat.m[3][2] - mat.m[0][3] * mat.m[1][0] * mat.m[2][1] * mat.m[3][2] + mat.m[0][0] * mat.m[1][3] * mat.m[2][1] * mat.m[3][2] +
		mat.m[0][1] * mat.m[1][0] * mat.m[2][3] * mat.m[3][2] - mat.m[0][0] * mat.m[1][1] * mat.m[2][3] * mat.m[3][2] - mat.m[0][2] * mat.m[1][1] * mat.m[2][0] * mat.m[3][3] + mat.m[0][1] * mat.m[1][2] * mat.m[2][0] * mat.m[3][3] +
		mat.m[0][2] * mat.m[1][0] * mat.m[2][1] * mat.m[3][3] - mat.m[0][0] * mat.m[1][2] * mat.m[2][1] * mat.m[3][3] - mat.m[0][1] * mat.m[1][0] * mat.m[2][2] * mat.m[3][3] + mat.m[0][0] * mat.m[1][1] * mat.m[2][2] * mat.m[3][3];
	return det;
}




ajax.math.Matrix.scale                       = function(mat, scale)
{        
	for (var i = 0; i < 4; i++)			
		for (var j = 0; j < 4; j++)
			mat.m[i][j] *= scale;	
}

ajax.math.Matrix.multiply                    = function(a, b)
{///<returns type="ajax.math.Matrix"/>
	var result = new ajax.math.Matrix();
	for (var i = 0; i < 4; i++)
	{
		for (var j = 0; j < 4; j++)
		{
			result.m[i][j] = 0;
			for (var k = 0; k < 4; k++)
			{
				result.m[i][j] += a.m[i][k] * b.m[k][j];
			}
		}
	}
	return result;
}





ajax.math.Matrix.transpose                   = function(original)
{///<returns type="ajax.math.Matrix"/>
	var result = new ajax.math.Matrix();
	for (var i = 0; i < 4; i++)
		for (var j = 0; j < 4; j++)
			result.m[i][j] = original.m[j][i];
	
	return result;
}


ajax.math.Matrix.transposeAdjoint            = function(mat)
{///<returns type="ajax.math.Matrix"/>
	var adjoint = new ajax.math.Matrix();
	adjoint.m[0][0] = mat.m[1][1] * mat.m[2][2] - mat.m[1][2] * mat.m[2][1] ;
	adjoint.m[0][1] = mat.m[1][2] * mat.m[2][0] - mat.m[1][0] * mat.m[2][2] ;
	adjoint.m[0][2] = mat.m[1][0] * mat.m[2][1] - mat.m[1][1] * mat.m[2][0] ;
	adjoint.m[1][0] = mat.m[2][1] * mat.m[0][2] - mat.m[2][2] * mat.m[0][1] ;
	adjoint.m[1][1] = mat.m[2][2] * mat.m[0][0] - mat.m[2][0] * mat.m[0][2] ;
	adjoint.m[1][2] = mat.m[2][0] * mat.m[0][1] - mat.m[2][1] * mat.m[0][0] ;
	adjoint.m[2][0] = mat.m[0][1] * mat.m[1][2] - mat.m[0][2] * mat.m[1][1] ;
	adjoint.m[2][1] = mat.m[0][2] * mat.m[1][0] - mat.m[0][0] * mat.m[1][2] ;
	adjoint.m[2][2] = mat.m[0][0] * mat.m[1][1] - mat.m[0][1] * mat.m[1][0] ;
	
	return adjoint;
}






ajax.math.Matrix.transformVertices           = function(mat, vb)
{///<returns type="Array" elementType="ajax.math.Vector3"/>
	var result = new Array(vb.length);
	var x = 0;
	var y = 0;
	var z = 0;

	// Loop through each vertex and apply the matrix to it
	for (var i = 0; i < vb.length; i++)
	{	    
		x = (mat.m[0][0] * vb[i].x) + (mat.m[1][0] * vb[i].y) + (mat.m[2][0] * vb[i].z) + mat.m[3][0];
		y = (mat.m[0][1] * vb[i].x) + (mat.m[1][1] * vb[i].y) + (mat.m[2][1] * vb[i].z) + mat.m[3][1];
		z = (mat.m[0][2] * vb[i].x) + (mat.m[1][2] * vb[i].y) + (mat.m[2][2] * vb[i].z) + mat.m[3][2];
		result[i] = new ajax.math.Vector3(x, y, z);
	}
	return result;
}

ajax.math.Matrix.transformVertex             = function(mat, vertex)
{///<returns type="ajax.math.Vector3"/>
	return new ajax.math.Vector3(
		(mat.m[0][0] * vertex.x) + (mat.m[1][0] * vertex.y) + (mat.m[2][0] * vertex.z) + mat.m[3][0],
		(mat.m[0][1] * vertex.x) + (mat.m[1][1] * vertex.y) + (mat.m[2][1] * vertex.z) + mat.m[3][1],
		(mat.m[0][2] * vertex.x) + (mat.m[1][2] * vertex.y) + (mat.m[2][2] * vertex.z) + mat.m[3][2]
		);	
}

ajax.math.Matrix.transformFaceNormals        = function(mat, faces)
{///<returns type="Array" elementType="ajax.math.Vector3">Returns an array of vectors, one for each face, that are the Transformed normals for the given matrix</returns>
	var normals = new Array(faces.length);	

	for (var i = 0; i < faces.length; i++)
	{
		var face = faces[i];

		// Use only the rotation values from the matrix NOT scaling
		normals[i] = ajax.math.Matrix.transformNormal(mat, face.normal);
	}

	return normals;
}

ajax.math.Matrix.transformNormal             = function(mat, normal)
{///<returns type="ajax.math.Vector3"/>
	var result = new ajax.math.Vector3(
		(mat.m[0][0] * normal.x) + (mat.m[1][0] * normal.y) + (mat.m[2][0] * normal.z),
		(mat.m[0][1] * normal.x) + (mat.m[1][1] * normal.y) + (mat.m[2][1] * normal.z),
		(mat.m[0][2] * normal.x) + (mat.m[1][2] * normal.y) + (mat.m[2][2] * normal.z)				
		);
    // As long as what was passed in was a normal, this should not be needed.
	//result.normalize();
	return result;
}




// More statics
ajax.math.Matrix.getRightUnitVector = function(mat)
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(mat.m[0][0], mat.m[0][1], mat.m[0][2]);
}
ajax.math.Matrix.getUpUnitVector    = function(mat)
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(mat.m[1][0], mat.m[1][1], mat.m[1][2]);
}
ajax.math.Matrix.getForwardUnitVector = function(mat)
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(mat.m[2][0], mat.m[2][1], mat.m[2][2]);
}
ajax.math.Matrix.getPositionVector = function(mat)
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(mat.m[3][0], mat.m[3][1], mat.m[3][2]);
}
ajax.math.Matrix.setPositionVector = function(mat, posVector)
{
    mat.m[3][0] = posVector.x;
    mat.m[3][1] = posVector.y;
    mat.m[3][2] = posVector.z;
}

ajax.math.Matrix.getScaleVector = function(mat)
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(mat.m[0][0], mat.m[1][1], mat.m[2][2]);
}

ajax.math.Matrix.setScaleVector = function(mat, vec)
{///<param name="vec" type="ajax.math.Vector3"/>
    mat.m[0][0] = vec.x;
    mat.m[1][1] = vec.y, 
    mat.m[2][2] = vec.z;
}

// Member versions
ajax.math.Matrix.prototype.getRightUnitVector = function()
{///<returns type="ajax.math.Vector3"/>
    return ajax.math.Matrix.getRightUnitVector(this);
}
ajax.math.Matrix.prototype.getUpUnitVector = function()
{///<returns type="ajax.math.Vector3"/>
    return ajax.math.Matrix.getUpUnitVector(this);
}
ajax.math.Matrix.prototype.getForwardUnitVector = function()
{///<returns type="ajax.math.Vector3"/>
    return ajax.math.Matrix.getForwardUnitVector(this);
}
ajax.math.Matrix.prototype.getPositionVector = function()
{///<returns type="ajax.math.Vector3"/>
    return ajax.math.Matrix.getPositionVector(this);
}
ajax.math.Matrix.prototype.setPositionVector = function(posVector)
{
    ajax.math.Matrix.setPositionVector(this, posVector)
}

ajax.math.Matrix.prototype.getScaleVector = function()
{///<returns type="ajax.math.Vector3"/>
    return ajax.math.Matrix.getScaleVector(this);
}

ajax.math.Matrix.prototype.setScaleVector = function(vec)
{///<param name="vec" type="ajax.math.Vector3"/>
    ajax.math.Matrix.setScaleVector(this, vec);
}

// Projection
ajax.math.Matrix.createPerspectiveFieldOfView = function(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance)
{///<returns type="ajax.math.Matrix"/>
    var matrix = new ajax.math.Matrix();
    if (fieldOfView <= 0 || fieldOfView >= ajax.geometry.Math.pi)
        ajax.debug.Output.writeLn("Error: Out of range fileOfView");
    if (nearPlaneDistance < 0)
        ajax.debug.Output.writeLn("Error: Negative near plane distance");
    if (farPlaneDistance < 0)
        ajax.debug.Output.writeLn("Error: Negative far plane distance");
    if (nearPlaneDistance >= farPlaneDistance)
        ajax.debug.Output.writeLn("Error: Out of range planes.");
    
    var num = 1 / parseFloat( Math.tan(parseFloat(fieldOfView * 0.5)) );
    var num9 = num / aspectRatio;
    matrix.m[0][0] = num9;// num; // When testing XNA appeared to use "num" rather than "num9". Reflector said otherwise + using num gives a squashed result??
    matrix.m[0][1] = matrix.m[0][2] = matrix.m[0][3] = 0;
    
    matrix.m[1][1] = num;
    matrix.m[1][0] = matrix.m[1][2] = matrix.m[1][3] = 0;
    
    matrix.m[2][0] = matrix.m[2][1] = 0;        
    matrix.m[2][2] = farPlaneDistance / (nearPlaneDistance - farPlaneDistance);    
    matrix.m[2][3] = -1; 
       
    matrix.m[3][0] = matrix.m[3][1] = matrix.m[3][3] = 0;    
    matrix.m[3][2] = (nearPlaneDistance * farPlaneDistance) / (nearPlaneDistance - farPlaneDistance);
    
    return matrix;
}

// Shadow
ajax.math.Matrix.createShadow = function(lightDirection, plane)
{///<summary>Creates a Matrix that flattens geometry into a specified Plane as if casting a shadow from a specified light source. </summary>
    ///<param name="lightDirection" type="ajax.math.Vector3">A Vector3 specifying the direction from which the light that will cast the shadow is coming.</param>
    ///<param name="plane" type="ajax.math.Plane3">The Plane onto which the new matrix should flatten geometry so as to cast a shadow.</param>
    ///<returns type="ajax.math.Matrix"/>
        
    lightDirection = ajax.math.Vector3.cast(lightDirection);
    plane = ajax.math.Plane3.cast(plane);
    
    var matrix = new ajax.math.Matrix();
    var plane2 = ajax.math.Plane3.cast(plane);
    
    var num = ((plane2.normal.x * lightDirection.x) + (plane2.normal.y * lightDirection.y)) + (plane2.normal.z * lightDirection.z);
    var num5 = -plane2.normal.x;
    var num4 = -plane2.normal.y;
    var num3 = -plane2.normal.z;
    var num2 = -plane2.distance;
    matrix.m[0][0] = (num5 * lightDirection.x) + num;
    matrix.m[1][0] = num4 * lightDirection.x;
    matrix.m[2][0] = num3 * lightDirection.x;
    matrix.m[3][0] = num2 * lightDirection.x;
    matrix.m[0][1] = num5 * lightDirection.y;
    matrix.m[1][1] = (num4 * lightDirection.y) + num;
    matrix.m[2][1] = num3 * lightDirection.y;
    matrix.m[3][1] = num2 * lightDirection.y;
    matrix.m[0][2] = num5 * lightDirection.z;
    matrix.m[1][2] = num4 * lightDirection.z;
    matrix.m[2][2] = (num3 * lightDirection.z) + num;
    matrix.m[3][2] = num2 * lightDirection.z;
    matrix.m[0][3] = 0;
    matrix.m[1][3] = 0;
    matrix.m[2][3] = 0;
    matrix.m[3][3] = num;
    return matrix;


 
}

ajax.math.Matrix.createLookAt = function(cameraPosition, cameraTarget, cameraUpVector)
{///<summary>Creates a view matrix.</summary>
///<param name="cameraPosition" type="ajax.math.Vector3">The position of the camera.</param>
///<param name="cameraTarget" type="ajax.math.Vector3">The direction that the camera is pointing.</param>
///<param name="cameraUpVector" type="ajax.math.Vector3">The direction that is "up" from the camera's point of view.</param>
///<returns type="ajax.math.Matrix"/>
    // TODO port this code...
    var Vector3 = ajax.math.Vector3;    
    var vector = Vector3.normalize(Vector3.subtract(cameraPosition, cameraTarget)); // Direction
    var vector2 = Vector3.normalize(Vector3.cross(cameraUpVector, vector)); // Right
    var vector3 = Vector3.cross(vector, vector2); // up again...???
    var matrix = new ajax.math.Matrix();
    matrix.m[0][0] = vector2.x;
    matrix.m[0][1] = vector3.x;
    matrix.m[0][2] = vector.x;
    matrix.m[0][3] = 0;
    matrix.m[1][0] = vector2.y;
    matrix.m[1][1] = vector3.y;
    matrix.m[1][2] = vector.y;
    matrix.m[1][3] = 0;
    matrix.m[2][0] = vector2.z;
    matrix.m[2][1] = vector3.z;
    matrix.m[2][2] = vector.z;
    matrix.m[2][3] = 0;
    matrix.m[3][0] = -Vector3.dot(vector2, cameraPosition);
    matrix.m[3][1] = -Vector3.dot(vector3, cameraPosition);
    matrix.m[3][2] = -Vector3.dot(vector, cameraPosition);
    matrix.m[3][3] = 1;
    return matrix;    
}




//
// Publish vars Hook up statics as instance methods also
ajax.math.Matrix.prototype.m                      = ajax.lang.multiDimensionalArray(4, 4);
ajax.math.Matrix.prototype.identity               = ajax.math.Matrix.identity; 
ajax.math.Matrix.prototype.scaling                = ajax.math.Matrix.scaling;
ajax.math.Matrix.prototype.translation            = ajax.math.Matrix.translation;
		
ajax.math.Matrix.prototype.rotateX                = ajax.math.Matrix.rotateX;
ajax.math.Matrix.prototype.rotateY                = ajax.math.Matrix.rotateY;
ajax.math.Matrix.prototype.rotateZ                = ajax.math.Matrix.rotateZ;
	
ajax.math.Matrix.prototype.rotateYawPitchRoll     = ajax.math.Matrix.rotateYawPitchRoll;
ajax.math.Matrix.prototype.transpose              = ajax.math.Matrix.transpose;	
ajax.math.Matrix.prototype.transposeAdjoint       = ajax.math.Matrix.transposeAdjoint;

//Xna like..
ajax.math.Matrix.createRotationX = ajax.math.Matrix.rotateX;
ajax.math.Matrix.createRotationY = ajax.math.Matrix.rotateY;
ajax.math.Matrix.createRotationZ = ajax.math.Matrix.rotateZ;
ajax.math.Matrix.createFromYawPitchRoll = ajax.math.Matrix.rotateYawPitchRoll;
ajax.math.Matrix.createTranslation = ajax.math.Matrix.translation;
ajax.math.Matrix.createScale = ajax.math.Matrix.scaling;
